package ink.xiaobaibai.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ink.xiaobaibai.bo.*;
import ink.xiaobaibai.common.ReportType;
import ink.xiaobaibai.dao.ReportClientOrderDao;
import ink.xiaobaibai.entity.*;
import ink.xiaobaibai.service.*;
import ink.xiaobaibai.serviceOxy.onePay.IUploadService;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xiaobaibai
 * @since 2021-05-28
 */
@Service
public class ReportClientOrderServiceImpl extends ServiceImpl<ReportClientOrderDao, ReportClientOrder> implements IReportClientOrderService {

    static {
        try {
            baseUrl =
                    new File(ResourceUtils.getURL("classpath:").getPath()).getParentFile().getParentFile().getParent();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Autowired
    private IAdminUserService adminUserService;

    @Autowired
    private IDepartmentService departmentService;

    @Autowired
    private IOzoneDeviceService ozoneDeviceService;

    @Autowired
    private IClientOrderService clientOrderService;

    @Autowired
    private IUploadService uploadService;

    @Autowired
    private IReportClientOrderService reportClientOrderService;

    @Autowired
    private IReportMonthlyOrderService reportMonthlyOrderService;

    @Autowired
    private IMonthlyfeeOrderService monthlyfeeOrderService;

    @Autowired
    private IBuyOrderService buyOrderService;

    @Autowired
    private IReportBuyOrderService reportBuyOrderService;

    @Autowired
    private IClientUserService clientUserService;

    @Autowired
    private ILogisticsService logisticsService;

    @Autowired
    private ILogisticsBuyService logisticsBuyService;

    /**
     * 月初的自动生成报表
     */
    @Override
    public void autoGenerateReportOrder() {
        this.init();
        this.start();
        this.destroy();
    }

    /**
     * 返回此报表可下载的url
     */
    @Override
    public String getReportUrl(String publicUrl) {
        return this.uploadService.getPrivateUrl(publicUrl);
    }

    /**
     * 文件地址
     */
    private static String baseUrl;
    /**
     * 起始时间
     */
    private Date startTime;
    /**
     * 结束时间
     */
    private Date endTime;
    /**
     * 时间字段
     */
    private String time;
    /**
     * 管理员id和[姓名+手机号]对应
     */
    private Map<Integer, AdminUser> userMap;
    /**
     * 部门id和部门名称对应
     */
    private Map<Integer, String> depMap;

    /**
     * 单次人员id和[昵称+手机号]
     */
    private Map<Integer, ClientUser> clientUserMap;

    private void init() {
        this.clientUserMap = new HashMap<>();
        //初始化用户id-name
        QueryWrapper<AdminUser> q1 = new QueryWrapper<>();
        q1.select("id", "user_name", "user_phone");
        List<AdminUser> userList = this.adminUserService.list(q1);
        this.userMap = new HashMap<>(userList.size());
        for (AdminUser adminUser : userList) {
            this.userMap.put(adminUser.getId(), adminUser);
        }
        //初始化部门id-name
        QueryWrapper<Department> q2 = new QueryWrapper<>();
        q2.select("id", "department_name");
        List<Department> departmentList = this.departmentService.list(q2);
        this.depMap = new HashMap<>(departmentList.size());
        for (Department department : departmentList) {
            this.depMap.put(department.getId(), department.getDepartmentName());
        }
        //时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, -1);
        this.time = DateFormatUtils.format(calendar.getTime(), "yyyy-MM");
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        String startTimeStr = DateFormatUtils.format(calendar.getTime(), "yyyy-MM-dd 00:00:00");
        try {
            this.startTime = DateUtils.parseDate(startTimeStr, "yyyy-MM-dd HH:mm:ss");
        } catch (ParseException e) {
            this.log.error("严重错误:时间转换出现错误");
            e.printStackTrace();
            this.startTime = calendar.getTime();
        }
        calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        String endTimeStr = DateFormatUtils.format(calendar.getTime(), "yyyy-MM-dd 23:59:59");
        try {
            this.endTime = DateUtils.parseDate(endTimeStr, "yyyy-MM-dd HH:mm:ss");
        } catch (ParseException e) {
            this.log.error("严重错误:时间转换出现错误");
            e.printStackTrace();
            this.endTime = new Date();
        }
        //初始化完毕
    }

    private void start() {
        /**
         * 单次支付
         */
        this.generateOnePayDeviceReportForm();
        this.generateOnePayPersonalReportForm();
        this.generateOnePayDepartmentReportForm();
        /**
         * 包月支付
         * 1.个人业绩 包月订单数据记录
         * 2.部门业绩 包月订单数据记录
         */
        this.generateMonthlyPersonalReportForm();
        this.generateMonthlyDepartmentReportForm();
        /**
         * 购买支付
         * 1.个人业绩
         * 2.部门业绩
         */
        this.generateBuyPersonalReportForm();
        this.generateBuyDepartmentReportForm();
    }

    private void destroy() {
        //GC
        this.userMap.clear();
        this.userMap = null;
        this.depMap.clear();
        this.depMap = null;
        this.time = null;
        this.startTime = null;
        this.endTime = null;
        this.clientUserMap.clear();
        this.clientUserMap = null;
    }

    private void generateOnePayDeviceReportForm() {
        //自动生成机器报表
        QueryWrapper<OzoneDevice> q1 = new QueryWrapper<>();
        q1.select("id");
        List<Integer> deviceIdList = this.ozoneDeviceService.list(q1).stream().map(OzoneDevice::getId).collect(Collectors.toList());
        String type = ReportType.DEVICE.getType();
        for (Integer deviceId : deviceIdList) {
            //对每个机器都去订单表中遍历,找到上个月时间段的订单
            List<ClientOrderHaveCodeBo> orderBoList = this.clientOrderService.getOrderBoListByDeviceId(deviceId, this.startTime, this.endTime);
            if (orderBoList.size() == 0) {
                //本台机器无业绩
                QueryWrapper<OzoneDevice> q2 = new QueryWrapper<>();
                q2.select("device_code");
                q2.eq("id", deviceId);
                OzoneDevice ozoneDevice = this.ozoneDeviceService.getOne(q2);
                ReportClientOrder reportClientOrder = new ReportClientOrder("机器", ozoneDevice.getDeviceCode(), this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportClientOrder);
                continue;
            }
            // 为每个对象放入 负责人手机号和用户手机号和用户昵称

            String typeId = orderBoList.get(0).getDeviceCode();
            this.onePayConvertUpSave(orderBoList, type, typeId);
            //结束本次机器循环
        }

    }

    private void generateOnePayPersonalReportForm() {
        //自动生成个人报表
        String type = ReportType.PERSONAL.getType();
        for (Map.Entry<Integer, AdminUser> entry : this.userMap.entrySet()) {
            String typeId = entry.getValue().getUserName();
            //负责人id
            Integer userId = entry.getKey();
            //当前人员上月的订单
            List<ClientOrderHaveCodeBo> list = this.clientOrderService.getOrderBoListByAdminUserId(userId, this.startTime, this.endTime);
            if (list.size() == 0) {
                //当前人员上月无订单
                ReportClientOrder reportClientOrder = new ReportClientOrder(type, typeId, this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportClientOrder);
                continue;
            }
            this.onePayConvertUpSave(list, type, typeId);
            //结束本次人员循环
        }
    }

    private void generateOnePayDepartmentReportForm() {
        //自动生成部门报表
        String type = ReportType.DEPARTMENT.getType();
        for (Map.Entry<Integer, String> entry : this.depMap.entrySet()) {
            //部门id
            Integer depId = entry.getKey();
            //部门名称
            String typeId = entry.getValue();
            //当前部门上个月的订单
            List<ClientOrderHaveCodeBo> list = this.clientOrderService.getOrderBoListByDepId(depId, this.startTime, this.endTime);
            if (list.size() == 0) {
                //当前部门上月无订单
                ReportClientOrder reportClientOrder = new ReportClientOrder(type, typeId, this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportClientOrder);
                continue;
            }
            this.onePayConvertUpSave(list, type, typeId);
            //结束本次部门循环
        }
    }

    /**
     * 包月 个人业绩
     */
    private void generateMonthlyPersonalReportForm() {
        //自动生成个人报表
        String type = ReportType.PERSONAL.getType();
        for (Map.Entry<Integer, AdminUser> entry : this.userMap.entrySet()) {
            String typeId = entry.getValue().getUserName();
            //负责人id
            Integer userId = entry.getKey();
            //当前人员上月的订单
            List<MonthlyOrderHaveCodeBo> list = this.monthlyfeeOrderService.getOrderBoListByAdminUserId(userId, this.startTime, this.endTime);
            if (list.size() == 0) {
                //当前人员上月无订单
                ReportMonthlyOrder reportMonthlyOrder = new ReportMonthlyOrder(type, typeId, this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportMonthlyOrder);
                continue;
            }
            this.monthlyConvertUpSave(list, type, typeId);
            //结束本次人员循环
        }
    }

    /**
     * 包月 部门业绩
     */
    private void generateMonthlyDepartmentReportForm() {
        //自动生成部门报表
        String type = ReportType.DEPARTMENT.getType();
        for (Map.Entry<Integer, String> entry : this.depMap.entrySet()) {
            //部门id
            Integer depId = entry.getKey();
            //部门名称
            String typeId = entry.getValue();
            //当前部门上个月的订单
            List<MonthlyOrderHaveCodeBo> list = this.monthlyfeeOrderService.getOrderBoListByDepId(depId, this.startTime, this.endTime);
            if (list.size() == 0) {
                //当前部门上月无订单
                ReportMonthlyOrder reportMonthlyOrder = new ReportMonthlyOrder(type, typeId, this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportMonthlyOrder);
                continue;
            }
            this.monthlyConvertUpSave(list, type, typeId);
            //结束本次部门循环
        }
    }

    /**
     * 购买 个人业绩
     */
    private void generateBuyPersonalReportForm() {
        //自动生成个人报表
        String type = ReportType.PERSONAL.getType();
        for (Map.Entry<Integer, AdminUser> entry : this.userMap.entrySet()) {
            String typeId = entry.getValue().getUserName();
            //负责人id
            Integer userId = entry.getKey();
            //当前人员上月的订单
            QueryWrapper<BuyOrder> q1 = new QueryWrapper<>();
            q1.eq("admin_user_id", userId);
            q1.between("create_time", this.startTime, this.endTime);
            List<BuyOrder> list = this.buyOrderService.list(q1);
            if (list.size() == 0) {
                //当前人员上月无订单
                ReportBuyOrder reportBuyOrder = new ReportBuyOrder(type, typeId, this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportBuyOrder);
                continue;
            }
            this.buyConvertUpSave(list, type, typeId);
            //结束本次人员循环
        }
    }

    /**
     * 购买 部门业绩
     */
    private void generateBuyDepartmentReportForm() {
        //自动生成部门报表
        String type = ReportType.DEPARTMENT.getType();
        for (Map.Entry<Integer, String> entry : this.depMap.entrySet()) {
            //部门id
            Integer depId = entry.getKey();
            //部门名称
            String typeId = entry.getValue();
            //当前部门上个月的订单
            QueryWrapper<BuyOrder> q1 = new QueryWrapper<>();
            q1.eq("admin_dep_id", depId);
            q1.between("create_time", this.startTime, this.endTime);
            List<BuyOrder> list = this.buyOrderService.list(q1);
            if (list.size() == 0) {
                //当前部门上月无订单
                ReportBuyOrder reportBuyOrder = new ReportBuyOrder(type, typeId, this.time, "无业绩", new BigDecimal(0));
                this.saveReport(reportBuyOrder);
                continue;
            }
            this.buyConvertUpSave(list, type, typeId);
            //结束本次部门循环
        }
    }

    private OnePayReportFormBo clientOrderConvertReportFormBo(ClientOrderHaveCodeBo clientOrderHaveCodeBo) {
        ClientUser clientUser = this.clientUserMap.get(clientOrderHaveCodeBo.getUserId());
        AdminUser adminUser = this.userMap.get(clientOrderHaveCodeBo.getAdminUserId());
        return new OnePayReportFormBo(
                clientOrderHaveCodeBo.getId(),
                clientOrderHaveCodeBo.getUserId(),
                clientOrderHaveCodeBo.getOrderAmount(),
                clientOrderHaveCodeBo.getDeviceCode(),
                adminUser.getUserName(),
                this.depMap.get(clientOrderHaveCodeBo.getAdminDepId()),
                clientOrderHaveCodeBo.getCreateTime(),
                clientUser.getUserNickname(),
                clientUser.getUserPhone(),
                adminUser.getUserPhone()
        );
    }

    private MonthlyReportFormBo monthlyOrderConvertReportFormBo(MonthlyOrderHaveCodeBo monthlyOrderHaveCodeBo) {
        AdminUser adminUser = this.userMap.get(monthlyOrderHaveCodeBo.getAdminUserId());
        Logistics logistics = this.getMonthlyClientUser(monthlyOrderHaveCodeBo.getLogisticsId());
        return new MonthlyReportFormBo(
                monthlyOrderHaveCodeBo.getOrderId(),
                logistics.getName(),
                monthlyOrderHaveCodeBo.getOrderAmount(),
                monthlyOrderHaveCodeBo.getDeviceCode(),
                this.userMap.get(monthlyOrderHaveCodeBo.getUserId()).getUserName(),
                this.depMap.get(monthlyOrderHaveCodeBo.getAdminDepId()),
                monthlyOrderHaveCodeBo.getCreateTime(),
                logistics.getPhone(),
                logistics.getAddress(),
                adminUser.getUserPhone()
        );
    }

    private BuyReportFormBo buyOrderConvertReportFormBo(BuyOrder buyOrder) {
        LogisticsBuy buyClientUser = this.getBuyClientUser(buyOrder.getLogisticsBuyId());
        AdminUser adminUser = this.userMap.get(buyOrder.getAdminUserId());
        return new BuyReportFormBo(
                buyOrder.getOrderId(),
                buyOrder.getAmount(),
                buyOrder.getDeviceId(),
                buyOrder.getDeviceCode(),
                buyClientUser.getName(),
                adminUser.getUserName(),
                this.depMap.get(buyOrder.getAdminDepId()),
                buyOrder.getCreateTime(),
                buyClientUser.getPhone(),
                buyClientUser.getAddress(),
                adminUser.getUserPhone()
        );
    }

    /**
     * 生成excel
     * 保存后,返回文件名
     * type: 机器/个人/部门
     * msg: 机器识别码/个人名字/部门名字
     */
    private String generateOnePayExcel(List<OnePayReportFormBo> list, String type, String msg, BigDecimal sumAmount) {
        list.get(0).setSumAmount(sumAmount);
        //例: /2020-01-机器-机器码 /2020-01-人员-小王
        String fileName = this.time + "-" + type + "-" + msg + ".xlsx";
        String filePath = baseUrl + "/" + fileName;
        EasyExcel.write(filePath, OnePayReportFormBo.class).sheet(msg).doWrite(list);
        return fileName;
    }

    private String generateMonthlyExcel(List<MonthlyReportFormBo> list, String type, String msg, BigDecimal sumAmount) {
        list.get(0).setSumAmount(sumAmount);
        //例: /2020-01-机器-机器码 /2020-01-人员-小王
        String fileName = this.time + "-" + type + "-" + msg + ".xlsx";
        String filePath = baseUrl + "/" + fileName;
        EasyExcel.write(filePath, MonthlyReportFormBo.class).sheet(msg).doWrite(list);
        return fileName;
    }

    private String generateBuyExcel(List<BuyReportFormBo> list, String type, String msg, BigDecimal sumAmount) {
        list.get(0).setSumAmount(sumAmount);
        //例: /2020-01-机器-机器码 /2020-01-人员-小王
        String fileName = this.time + "-" + type + "-" + msg + ".xlsx";
        String filePath = baseUrl + "/" + fileName;
        EasyExcel.write(filePath, BuyReportFormBo.class).sheet(msg).doWrite(list);
        return fileName;
    }

    /**
     * 将文件对象上传至七牛云,然后删除文件
     */
    private String uploadFile(String myFileName) {
        String filePath = baseUrl + "/" + myFileName;
        String httpUrl = this.uploadService.upload(filePath, myFileName);
        File file = new File(filePath);
        file.delete();
        return httpUrl;
    }

    /**
     * 保存单次文件信息
     */
    private void saveReport(ReportClientOrder reportClientOrder) {
        this.reportClientOrderService.save(reportClientOrder);
    }

    /**
     * 保存包月文件信息
     */
    private void saveReport(ReportMonthlyOrder reportMonthlyOrder) {
        this.reportMonthlyOrderService.save(reportMonthlyOrder);
    }

    /**
     * 保存包月文件信息
     */
    private void saveReport(ReportBuyOrder reportBuyOrder) {
        this.reportBuyOrderService.save(reportBuyOrder);
    }

    /**
     * 单次: 转换-上传-保存
     */
    private void onePayConvertUpSave(List<ClientOrderHaveCodeBo> list, String type, String typeId) {
        BigDecimal sumAmount = new BigDecimal(0);
        List<OnePayReportFormBo> onePayReportFormBoList = new ArrayList<>(list.size());
        for (ClientOrderHaveCodeBo clientOrderHaveCodeBo : list) {
            onePayReportFormBoList.add(this.clientOrderConvertReportFormBo(clientOrderHaveCodeBo));
            sumAmount = sumAmount.add(clientOrderHaveCodeBo.getOrderAmount());
        }
        String fileName = this.generateOnePayExcel(onePayReportFormBoList, type, typeId, sumAmount);
        //使用七牛云上传此文件
        String httpUrl = this.uploadFile(fileName);
        //存储报表对象
        ReportClientOrder reportClientOrder = new ReportClientOrder(type, typeId, this.time, httpUrl, sumAmount);
        this.saveReport(reportClientOrder);
        //结束本次循环
    }

    /**
     * 包月: 转换-上传-保存
     */
    private void monthlyConvertUpSave(List<MonthlyOrderHaveCodeBo> list, String type, String typeId) {
        BigDecimal sumAmount = new BigDecimal(0);
        List<MonthlyReportFormBo> monthlyReportFormBoList = new ArrayList<>(list.size());
        for (MonthlyOrderHaveCodeBo monthlyOrderHaveCodeBo : list) {
            monthlyReportFormBoList.add(this.monthlyOrderConvertReportFormBo(monthlyOrderHaveCodeBo));
            sumAmount = sumAmount.add(monthlyOrderHaveCodeBo.getOrderAmount());
        }
        String fileName = this.generateMonthlyExcel(monthlyReportFormBoList, type, typeId, sumAmount);
        //使用七牛云上传此文件
        String httpUrl = this.uploadFile(fileName);
        //存储报表对象
        ReportMonthlyOrder reportMonthlyOrder = new ReportMonthlyOrder(type, typeId, this.time, httpUrl, sumAmount);
        this.saveReport(reportMonthlyOrder);
        //结束本次循环
    }

    /**
     * 购买: 转换-上传-保存
     */
    private void buyConvertUpSave(List<BuyOrder> list, String type, String typeId) {
        BigDecimal sumAmount = new BigDecimal(0);
        List<BuyReportFormBo> buyReportFormBoList = new ArrayList<>(list.size());
        for (BuyOrder buyOrder : list) {
            buyReportFormBoList.add(this.buyOrderConvertReportFormBo(buyOrder));
            sumAmount = sumAmount.add(buyOrder.getAmount());
        }
        String fileName = this.generateBuyExcel(buyReportFormBoList, type, typeId, sumAmount);
        //使用七牛云上传此文件
        String httpUrl = this.uploadFile(fileName);
        //存储报表对象
        ReportBuyOrder reportBuyOrder = new ReportBuyOrder(type, typeId, this.time, httpUrl, sumAmount);
        this.saveReport(reportBuyOrder);
        //结束本次循环
    }

    /**
     * 获取单次支付的客户信息
     */
    private ClientUser getClientUser(Integer clientUserId) {
        return this.clientUserMap.compute(clientUserId, (k, v) -> {
            if (v == null) {
                QueryWrapper<ClientUser> q1 = new QueryWrapper<>();
                q1.select("user_nickname", "user_phone");
                q1.eq("id", clientUserId);
                return this.clientUserService.getOne(q1);
            }
            return v;
        });
    }

    /**
     * 获取包月订单的客户信息
     */
    private Logistics getMonthlyClientUser(Integer id) {
        QueryWrapper<Logistics> q1 = new QueryWrapper<>();
        q1.select("name", "phone", "address");
        q1.eq("id", id);
        return this.logisticsService.getOne(q1);
    }

    private LogisticsBuy getBuyClientUser(Integer id) {
        QueryWrapper<LogisticsBuy> q1 = new QueryWrapper<>();
        q1.select("name", "phone", "address");
        q1.eq("id", id);
        return this.logisticsBuyService.getOne(q1);
    }

}
